package net.orange.framework.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import net.orange.architecture.db.Condition;
import net.orange.architecture.db.Conditions;
import net.orange.architecture.model.BaseValueObject;
import net.orange.architecture.process.ProcessFactory;
import net.orange.architecture.validator.NotDulicateValidator;
import net.orange.architecture.validator.ObjectNotNullValidator;
import net.orange.architecture.validator.StringNotNullValidator;
import net.orange.architecture.validator.Validator;
import net.orange.framework.logic.IDepartmentProcess;
import net.orange.framework.validator.DepartmentCodeFormatValidator;
import net.orange.framework.validator.DepartmentHasChildrenValidator;
import net.orange.framework.validator.DepartmentHasGroupValidator;
import net.orange.framework.validator.DepartmentHasUserValidator;
import net.orange.framework.validator.DepartmentParentValidator;

/**
 * The system department, which is tree hierarchy structure.It define the system
 * business organization chart. And it defined the user's report to relationship
 * and the data authority usually.
 */
@Entity
@Table(name = "t_department")
public class Department extends BaseValueObject {

	private static final long serialVersionUID = -8643764176742610038L;

	/**
	 * The department code.
	 */
	@Column(name = "dept_code")
	private String dept_code;

	/**
	 * The department name
	 */
	@Column(name = "dept_name")
	private String dept_name;

	/**
	 * The parent department
	 */
	@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
	@JoinColumn(name = "parent", insertable = true, updatable = true)
	private Department parent;

	/**
	 * The description
	 */
	@Column(name = "description")
	private String description;

	/**
	 * @return Returns the dept_code.
	 */
	public String getDept_code() {
		return dept_code;
	}

	/**
	 * @return Returns the dept_name.
	 */
	public String getDept_name() {
		return dept_name;
	}

	/**
	 * @return Returns the description.
	 */
	public String getDescription() {
		return description;
	}

	/**
	 * @param dept_code
	 *            The dept_code to set.
	 */
	public void setDept_code(String dept_code) {
		this.dept_code = dept_code;
	}

	/**
	 * @param dept_name
	 *            The dept_name to set.
	 */
	public void setDept_name(String dept_name) {
		this.dept_name = dept_name;
	}

	/**
	 * @param description
	 *            The description to set.
	 */
	public void setDescription(String description) {
		this.description = description;
	}

	/**
	 * @return Returns the parent.
	 */
	public Department getParent() {
		return parent;
	}

	/**
	 * @param parent
	 *            The parent to set.
	 */
	public void setParent(Department parent) {
		this.parent = parent;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.orange.architecture.model.BaseValueObject#satisfy(java.util.Collection
	 * )
	 */
	public boolean satisfy(Collection<String> msg) throws Exception {
		if (msg == null)
			msg = new ArrayList<String>();

		Validator validator = new Validator(msg);

		validator.add(new StringNotNullValidator(getDept_code(), "dept. code"));
		validator.add(new StringNotNullValidator(getDept_name(), "dept. name"));
		if (getDept_code() != null && !getDept_code().equals("D"))
			validator.add(new ObjectNotNullValidator(getParent(),
					"superior dept."));
		validator.add(new DepartmentCodeFormatValidator(this));
		validator.add(new DepartmentParentValidator(this));
		validator
				.add(new NotDulicateValidator(this, "dept_code", "department"));

		validator.validate();

		return (msg == null || msg.size() <= 0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.orange.architecture.model.BaseValueObject#canRemove(java.util.Collection
	 * )
	 */
	public boolean canRemove(Collection<String> msg) throws Exception {

		if (msg == null)
			msg = new ArrayList<String>();

		Validator validator = new Validator(msg);
		validator.add(new DepartmentHasChildrenValidator(this));
		validator.add(new DepartmentHasGroupValidator(this));
		validator.add(new DepartmentHasUserValidator(this));

		validator.validate();

		return (msg == null || msg.size() <= 0);
	}

	/**
	 * Retriever all the subordinate department list of special department.
	 * 
	 * @param department
	 *            The current department
	 * @return All the subordinate department list.
	 * @throws Exception
	 */
	public Collection getSubordinate() throws Exception {

		IDepartmentProcess process = (IDepartmentProcess) ProcessFactory
				.get(Department.class);
		Collection<Department> subordinates = new ArrayList<Department>();

		Conditions conditions = new Conditions();
		conditions.add(new Condition("parent", String.valueOf(this.getPk())));
		Collection c = process.listAll(conditions);

		if (c != null) {
			for (Iterator iter = c.iterator(); iter.hasNext();) {
				Department subordinate = (Department) iter.next();

				subordinates.addAll(subordinate.getSubordinate());
			}
		}

		subordinates.add(this);
		return subordinates;
	}
}